"use strict";
const path = require("path");
const Command = require("@yk-cli-dev/command");
const log = require("@yk-cli-dev/log");
const fs = require("fs");
const inquirer = require("inquirer");
const fsExtra = require("fs-extra");
const semver = require("semver");
const axios = require("axios");
const Package = require("@yk-cli-dev/package");
const { spinnerStart, sleep, execAsync } = require("@yk-cli-dev/utils");
const userHome = require("user-home");
const TYPE_PROJECT = "project";
const TYPE_COMPONENT = "component";
const TEMPLATE_TYPE_NORMAL = "normal";
const TEMPLATE_TYPE_CUSTOM = "custom";
const WHITE_COMMAND = ["npm", "cnpm", "pnpm", "yarn"];
class InitCommand extends Command {
  init() {
    this.projectName = this._argv[0] || "";
    this.force = !!this._cmd.force;
    if (process.env.LOG_LEVEL == "verbose") {
      log.info("projectName", this.projectName);
      log.info("force", this.force);
    }
  }
  async exec() {
    try {
      console.log('===================');
      //1.准备阶段
      const projectInfo = await this.prepare();
      console.log(projectInfo, "projectInfo");
      if (projectInfo) {
        this.projectInfo = projectInfo;
        //2.下载模版
        await this.downloadTemplate(projectInfo);
        //3.安装模版
        await this.installTemplate();
      }
    } catch (error) {
      log.error(error);
    }
  }
  async prepare() {
    //0 判断项目模版是否存在
    let template;
    template = [
      {
        _id: "65e973ce1446000057000ec3",
        name: "vue3标准模版",
        npmName: "yk-cli-template-vue3",
        version: "1.0.2",
        type: "normal",
        installCommand: "npm install",
        startCommand: "npm run serve",
        tag: ["project"],
        ignore: ["**/public/**"],
      },
      {
        _id: "65ead35d1446000057000ec4",
        name: "vue3标准组件模板模版",
        npmName: "yk-zujianfengzhuang",
        version: "1.0.0",
        type: "normal",
        installCommand: "npm install",
        startCommand: "npm run dev",
        tag: ["component"],
        ignore: ["**/public/**"],
      },
    ];
    // await axios
    //   .get("http://localhost:7002/project/template")
    //   .then((response) => {
    //     if (response.data.code == 200) {
    //       template = response.data.data;
    //     }
    //   })
    //   .catch((error) => {
    //     console.log(error, "error");
    //   });
    if (!template || template.length == 0) throw new Error("项目模板不存在");
    this.template = template;
    const localPath = process.cwd();
    let isContinue = false;
    //1.判断当前目录是否为空
    const ret = this.isCwdDirectoryEmpty(localPath);
    if (!ret) {
      if (!this.force) {
        //1.1 询问是否继续创建
        const ret = await inquirer.prompt({
          type: "confirm",
          message: "当前文件夹不为空，是否继续创建项目？",
          name: "isContinue",
          default: false,
        });
        isContinue = ret.isContinue;
        if (!isContinue) return;
      }
      //2.是否强制更新
      if (isContinue || this.force) {
        //给用户做二次确认
        const { confirmDelete } = await inquirer.prompt({
          type: "comfirm",
          message: "是否确认清空当前目录下的文件夹？",
          name: "confirmDelete",
          default: false,
        });
        if (confirmDelete) {
          // 删除文件夹
          fsExtra.emptyDirSync(localPath);
        }
        if (!confirmDelete && !this.force) return;
      }
    }
    return this.getProjectInfo();
  }
  async getProjectInfo() {
    function isValidName(v) {
      return /^(@[a-zA-Z0-9-_]+\/)?[a-zA-Z]+([-][a-zA-Z][a-zA-Z0-9]*|[_][a-zA-Z][a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(
        v
      );
    }
    let isProjectNameValid = false;
    let projectInfo = {};
    if (isValidName(this.projectName)) {
      isProjectNameValid = true;
      projectInfo.projectName = this.projectName;
    }
    //1.选择创建项目或组件
    const { type } = await inquirer.prompt({
      type: "list",
      message: "请选择要创建的项目类型",
      default: TYPE_PROJECT,
      choices: [
        { name: "项目", value: TYPE_PROJECT },
        { name: "组件", value: TYPE_COMPONENT },
      ],
      name: "type",
    });
    //过滤选择组件或者项目模板的列表
    this.template = this.template.filter((item) => item?.tag?.includes(type));
    const title = type === TYPE_PROJECT ? "项目" : "组件";
    const progjectPrompt = [
      {
        type: "input",
        name: "projectName",
        message: `请输入${title}名称`,
        default: "my-vue-app",
        validate: function (v) {
          const done = this.async();
          setTimeout(function () {
            if (
              !/^[a-zA-Z]+([-]+[a-zA-Z]+[a-zA-Z0-9]*|[_]+[a-zA-Z]+[a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(
                v
              )
            ) {
              // Pass the return value in the done callback
              done(`请输入合法的${title}名称`);
            } else {
              // Pass the return value in the done callback
              done(null, true);
            }
          }, 0);
          //首字符必须是英文字符
          //尾字符必须为英文或者数字，不能为字符
          //字符仅允许"-_"
          //合法：a, a-b,a-b-c,a-b1-c1
          //不合法：1,a_,a-,a-1
          return /^[a-zA-Z]+([-]+[a-zA-Z]+[a-zA-Z0-9]*|[_]+[a-zA-Z]+[a-zA-Z0-9]*|[a-zA-Z0-9])*$/.test(
            v
          );
        },
        filter: (v) => {
          return v;
        },
      },
      {
        type: "input",
        name: "projectVersion",
        message: `请输入${title}版本号`,
        default: "1.0.0",
        validate: function (v) {
          const done = this.async();
          setTimeout(function () {
            if (!!!semver.valid(v)) {
              // Pass the return value in the done callback
              done(`请输入合法的${title}版本号`);
            } else {
              // Pass the return value in the done callback
              done(null, true);
            }
          }, 0);
          if (!!semver.valid(v)) {
            return !!semver.valid(v);
          } else {
            return v;
          }
        },
        filter: (v) => {
          return v;
        },
      },
      {
        type: "list",
        name: "projectTemplate",
        message: `请选择${title}模板`,
        choices: this.createProjectTemplateChoices(),
      },
    ];
    if (type === TYPE_PROJECT) {
      if (isProjectNameValid) {
        progjectPrompt.splice(0, 1);
      }
      //2.获取项目的基本信息
      const project = await inquirer.prompt(progjectPrompt);
      projectInfo = {
        ...projectInfo,
        type,
        ...project,
      };
    } else if (type === TYPE_COMPONENT) {
      //2.获取组件的基本信息
      const component = await inquirer.prompt(progjectPrompt);
      projectInfo = {
        ...projectInfo,
        type,
        ...component,
      };
    }
    if (projectInfo.componentDescription) {
      projectInfo.description = projectInfo.componentDescription;
    }
    if (projectInfo.projectName) {
      projectInfo.className = require("kebab-case")(
        projectInfo.projectName
      ).replace(/^-/, "");
    }
    return projectInfo;
  }
  isCwdDirectoryEmpty(localPath) {
    let filelist = fs.readdirSync(localPath);
    filelist = filelist.filter(
      (file) =>
        !file.startsWith(".") && [".git", "node_modules"].indexOf(file) < 0
    );
    return !filelist || filelist.length <= 0;
  }
  //下载模版
  async downloadTemplate() {
    //1、通过项目模板api获取项目模版信息
    //1.1通过egg.js搭建一套后端系统
    //1.2通过npm储存项目模版
    //1.3 将项目模版信息储存到MongoDB数据库
    //1.4通过egg.js获取MongoDB中的数据通过api返回
    const { type, projectTemplate } = this.projectInfo;
    this.templateNameInfo = this.template.find(
      (item) => item.npmName === projectTemplate
    );
    const { npmName, version } = this.templateNameInfo;
    const targetPath = path.resolve(userHome, ".yk-cli-dev", "template");
    const storeDir = path.resolve(
      userHome,
      ".yk-cli-dev",
      "template",
      "node_modules"
    );
    const templateNpm = new Package({
      targetPath,
      storeDir,
      packageName: npmName,
      packageVersion: version,
    });

    if (!(await templateNpm.exists())) {
      const spinner = spinnerStart("正在下载模板...");
      try {
        await templateNpm.install();
        await sleep();
      } catch (e) {
        throw e;
      } finally {
        spinner.stop(true);
        if (await templateNpm.exists()) {
          log.success("下载模版成功");
          this.templateNpm = templateNpm;
        }
      }
    } else {
      const spinner = spinnerStart("正在更新模板...");
      try {
        await templateNpm.update();
        await sleep();
        log.success("更新模版成功");
      } catch (e) {
        throw e;
      } finally {
        spinner.stop(true);
        if (await templateNpm.exists()) {
          log.success("更新模版成功");
          this.templateNpm = templateNpm;
        }
      }
    }
  }
  //安装模版
  async installTemplate() {
    console.log(this.templateNameInfo, "this.template");
    console.log(this.templateNpm.cacheFilePath, "this.templateNpm");
    if (this.templateNameInfo) {
      if (!this.templateNameInfo.type) {
        this.templateNameInfo.type = TEMPLATE_TYPE_NORMAL;
      }
      if (this.templateNameInfo.type == TEMPLATE_TYPE_NORMAL) {
        //标准安装
        await this.installNormalTemplate();
      } else if (this.templateNameInfo.type == TEMPLATE_TYPE_CUSTOM) {
        //自定义安装
        await this.installCustomTemplate();
      } else {
        throw new Error("模版类型错误");
      }
    } else {
      throw new Error("项目模版不存在");
    }
  }
  async installNormalTemplate() {
    //拷贝模版到当前目录
    let spinner = spinnerStart("正在安装模版...");
    await sleep();
    try {
      const templatePath = path.resolve(
        this.templateNpm.cacheFilePath,
        "template"
      );
      const targetPath = path.resolve(
        process.cwd(),
        this.projectInfo.projectName
      );
      fsExtra.ensureDirSync(targetPath); //判断路径是否真实存在，不存在就创建
      fsExtra.ensureDirSync(templatePath);
      fsExtra.copySync(templatePath, targetPath);
      //安装依赖
      const { installCommand, startCommand } = this.templateNameInfo;
      if (installCommand && installCommand.length > 0) {
        const installCmd = installCommand.split(" ");
        const cmd = this.checkCommand(installCmd[0]);
        const args = installCmd.slice(1);
        if (cmd) {
          const ret = await execAsync(cmd, args, {
            cwd: path.resolve(process.cwd(), this.projectInfo.projectName),
            stdio: "inherit",
          });
          if (ret !== 0) {
            throw new Error("安装依赖失败");
          }
          spinner.stop(true);
        } else {
          throw new Error("安装依赖命令错误");
        }
      }
      //启动命令
      if (startCommand && startCommand.length > 0) {
        const startCmd = startCommand.split(" ");
        const cmd = this.checkCommand(startCmd[0]);
        const args = startCmd.slice(1);
        if (cmd) {
          const ret = await execAsync(cmd, args, {
            cwd: path.resolve(process.cwd(), this.projectInfo.projectName),
            stdio: "inherit",
          });
          if (ret !== 0) {
            throw new Error("启动失败");
          }
          spinner.stop(true);
        } else {
          throw new Error("启动命令不存在");
        }
      }
    } catch (error) {
      throw error;
    } finally {
      spinner.stop(true);
      log.success("模版安装成功");
    }
  }
  checkCommand(cmd) {
    // WHITE_COMMAND
    if (WHITE_COMMAND.includes(cmd)) {
      return cmd;
    }
    return null;
  }
  async installCustomTemplate() {
    console.log("安装自定义模版");
  }
  createProjectTemplateChoices() {
    return this.template.map((item) => {
      return {
        value: item.npmName,
        name: item.name,
      };
    });
  }
}
function init(args) {
  new InitCommand(args);
}
module.exports = init;
module.exports.InitCommand = InitCommand;
